/********************************************************************************
* Copyright (c) 2009, Matteo Pelati (matteo.pelati@gmail.com)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in the
*       documentation and/or other materials provided with the distribution.
*     * Neither the name of the <organization> nor the
*       names of its contributors may be used to endorse or promote products
*       derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Matteo Pelati ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**************************************************************************************/


#pragma once


#include <fstream>
#include <string>
#include <cstdlib>
#include <stdlib.h>
#include <stdio.h>
#include <vcclr.h>
#include "dbxml/DbXml.hpp"
#include "dbXmlLib.h"



using namespace DbXml;
using namespace System;
using namespace System::Collections::Generic;
using namespace std;



namespace BerkeleyDB { namespace Xml
{

	[Flags] public enum class DbXmlQueryContextFlags
	{
		None = 0,
		LazyDocs = DBXML_LAZY_DOCS,
		DocumentProjection = DBXML_DOCUMENT_PROJECTION,
		ReadCommitted = DB_READ_COMMITTED,
		ReadUncommitted = DB_READ_UNCOMMITTED,
		AcquireWriteLocks = DB_RMW,
		WellFormedOnly = DBXML_WELL_FORMED_ONLY
	};

	public enum class DbXmlQueryReturnType
	{
		DeadValues = 0,
		LiveValues = XmlQueryContext::LiveValues
	};

	public enum class DbXmlQueryEvalType
	{
		Eager = XmlQueryContext::Eager,
		Lazy = XmlQueryContext::Lazy
	};

	public ref class DbXmlNamespace 
	{
	private:
		String^ prefix;
		String^ uri;
	public:
		DbXmlNamespace(String^ prefix, String^ uri)
		{
			this->prefix = prefix;
			this->uri = uri;
		};
		property String^ Prefix
		{
			String^ get() {return this->prefix;}
		}
		property String^ Uri
		{
			String^ get() {return this->uri;}
		}
	};

	public ref class DbXmlNamespaceCollection
	{
	private:
		XmlQueryContext* n_qctx;

	internal:
		XmlQueryContext* GetInnerObject()
		{
			return n_qctx;
		}

		DbXmlNamespaceCollection(XmlQueryContext* ctx)
		{
			n_qctx = ctx;
		};

	public:
		void Set(DbXmlNamespace^ ns);
		DbXmlNamespace^ Get(String^ prefix);
		void Remove(String^ prefix);
		void Clear();
	};


	public ref class DbXmlQueryContext : public DbGenericObject
	{
	private:
		XmlQueryContext* n_qctx;
		DbXmlNamespaceCollection^ nsl;

		IDbXmlDatabaseItem^ Get_Variables(String^ value);
		void Set_Variables(String^ idx, IDbXmlDatabaseItem^ value);

	internal:
		XmlQueryContext* GetInnerObject()
		{
			return n_qctx;
		}
		
		/*
		DbXmlQueryContext(DbGenericObject^ parent, XmlQueryContext* n_qctx) : DbGenericObject(parent)
		{
			this->n_qctx = n_qctx;
			this->nsl = gcnew DbXmlNamespaceCollection(n_qctx);
		};
		*/

		DbXmlQueryContext(DbGenericObject^ parent, XmlQueryContext& n_qctx) : DbGenericObject(parent)
		{
			this->n_qctx = new XmlQueryContext(n_qctx);
			this->nsl = gcnew DbXmlNamespaceCollection(this->n_qctx);
		};

	public:
		~DbXmlQueryContext()
		{
			GC::SuppressFinalize(this);
			this->!DbXmlQueryContext();
		}
		!DbXmlQueryContext()
		{
			delete n_qctx;
		}
	public:

		// properties

		PROPERTY_RET_ENUM_BOTH(ReturnType,, ReturnType, DbXmlQueryReturnType, XmlQueryContext::ReturnType); 
		PROPERTY_RET_ENUM_BOTH(EvaluationType,, EvaluationType, DbXmlQueryEvalType, XmlQueryContext::EvaluationType); 
		PROPERTY_RET_UINT32_BOTH(TimeoutSeconds,, QueryTimeoutSeconds);
		PROPERTY_RET_CSTRING_BOTH(BaseURI,, BaseURI);
		PROPERTY_RET_CSTRING_BOTH(DefaultCollection,, DefaultCollection);

		property DbXmlNamespaceCollection^ Namespaces
		{
			DbXmlNamespaceCollection^ get()
			{
				return this->nsl;
			}
		}

		property IDbXmlDatabaseItem^ Variables[String^]
		{
			IDbXmlDatabaseItem^ get(String^ value) 
			{
				return this->Get_Variables(value);
			}
			void set(String^ idx, IDbXmlDatabaseItem^ value)
			{
				this->Set_Variables(idx, value);
			}
		}

		/*
		property IDbXmlDatabaseItem^ Variables[String^]
		{
			IDbXmlDatabaseItem^ get(String^ key)
			{
				try
				{
					CLRSTR2STDSTR(ckey, key);
					try
					{
						XmlValue outVal;
						if (!n_qctx->getVariableValue(ckey, outVal))
							return nullptr;
						return gcnew DbXmlValue(this, outVal);
					}
					catch(...)
					{
						
						XmlResults outValSet;
						if (!n_qctx->getVariableValue(ckey, outValSet))
							return nullptr;
						return gcnew DbXmlResults(this, outVal);
						
					}
				}
				rethrowDbXmlException();
			}

			void set(String^ key, IDbXmlDatabaseItem^ value)
			{
				try
				{
					
				}
				rethrowDbXmlException();
			}
		}
		*/

		// methods
		void InterruptQuery();

	};

}}